import WebGl from '@/modules/three';
import assets from '@/modules/assets';
import { createNoise2D } from '@/modules/local';
// import { FBXLoader } from 'threeJsm/loaders/FBXLoader.js';
import { FBXLoader } from 'threeJsm/loaders/FBXLoader.js';
import { EffectComposer } from 'threeJsm/postprocessing/EffectComposer.js';
import { RenderPass } from 'threeJsm/postprocessing/RenderPass.js';
import { BokehPass } from 'threeJsm/postprocessing/BokehPass.js';
import { RenderPixelatedPass } from 'threeJsm/postprocessing/RenderPixelatedPass.js';
import intf from '@/modules/interface';
import config from '@/config';
const { gsap } = intf;
const noise2D = createNoise2D();

const { Three, TWEEN, dat, Stats, OrbitControls, OBJLoader, MTLLoader } = WebGl;

const calcColor = new Three.Color();
const calcWaveColor = (x: number, y: number, z: number) => {
  //y: -300 ~ 300
  const l = (y + 150) / 700 - (Math.abs(x) / 300) * 0.2 - 0.0;
  calcColor.setHSL(
    // 0.5,
    z / 100 + 0.51,
    1.0,
    Math.max(0.1, l),
    Three.SRGBColorSpace,
  );
  return calcColor;
};

interface MeshsName {
  // testCube?: typeof Three.Mesh;
  // testBall?: typeof Three.Mesh;

  cube?: typeof Three.Mesh;
  sphere?: typeof Three.Mesh;
  wave?: typeof Three.Mesh;
  boat?: typeof Three.Mesh;
  lighthouse?: typeof Three.Mesh;
  bird?: typeof Three.Mesh;
  wheel?: typeof Three.Mesh;
}
type GeoType<T, Z> = {
  [K in keyof T]: Z;
};
type callbackTypes = 'afterLoad' | 'afterAnimate';

class WebGlControl {
  private container: any;
  private containerBg: any;
  private camera: any;
  private scene: any;
  private sceneBg: any;
  private rendererMain: any;
  private rendererBg: any;
  private stats: any;
  private animateFrame: any;
  private tween: any;
  private controls: any;
  private clock: any = new Three.Clock();
  private cameraFocusP = new Three.Vector3(0, 0, 0);
  private cameraP = new Three.Vector3(0, 160, 0);
  private lightHouseP = new Three.Vector3(40, 0, 50);
  private indexScrollGroup: any = new Three.Group();
  private boatGroup: any = new Three.Group();
  private tweenValues: { [key: string]: number } = {
    boatGpPositionState: 0,
    boatGpRotateY: 0,
  };
  private composePasses: any = {};
  private composer: any; //合成
  // private cameraTimeline:any;

  private Geometrys: GeoType<MeshsName, typeof Three.Object3D> = {}; //保存所有Geometry，方便统一销毁
  private Materials: GeoType<MeshsName, typeof Three.Object3D> = {}; //保存所有Material，方便统一销毁
  private Meshs: MeshsName = {};
  // private particleSystem: any;

  private textureLoader = new Three.TextureLoader();

  private GuiInit: any = null;
  private guiData: any = {
    // color: '#000000',
    testMode: false,
    enableMouseMove: false,

    speedX: -1,
    speedY: 0,
    scale: 0.22,
    // strength: 1,
    strength: 1.8,
    wavePointNum: 80, //

    focus: 65,
    aperture: 0.4,
    maxblur: 0.005,

    pixelSize: 1,
  };
  private mouseData: any = {
    mouseX: 0,
    mouseY: 0,
  };
  private heightRate = 0.051; //距camera50时，物体高度与屏幕高度的比值；
  private windowW: number = window.innerWidth;
  private windowH: number = window.innerHeight;
  private windowHalfX: number = window.innerWidth / 2;
  private windowHalfY: number = window.innerHeight / 2;

  /** 监听回调方法 **/
  private callbackFuns: { [name: string]: Function[] } = {};
  /**
   * 监听回调；1：加载完成
   * **/
  public onSubscribe = (
    name: callbackTypes,
    callback: (status?: number) => void,
  ) => {
    let arr = this.callbackFuns[name] || [];
    arr.push(callback);
    this.callbackFuns[name] = arr;
  };
  private triggerSubscribe = (name: callbackTypes, status?: number) => {
    if (this.callbackFuns[name] && this.callbackFuns[name].length > 0) {
      this.callbackFuns[name].forEach((fun) => {
        fun.call(this, status);
      });
    }
  };
  /** 监听回调方法 **/

  public init = (id: string) => {
    // if(this.scene) {return}
    this.containerBg = document.getElementById(id + '-bg');
    this.container = document.getElementById(id);
    let width = this.container.clientWidth,
      height = this.container.clientHeight;

    this.scene = new Three.Scene();
    // this.scene.fog = new Three.FogExp2( 0x365a74, 0.0075 );
    this.scene.backgroundBlurriness = 0.35;
    new Three.TextureLoader().load(assets.mainBackground, (texture) => {
      texture.mapping = Three.EquirectangularReflectionMapping;
      texture.colorSpace = Three.SRGBColorSpace;

      // pngCubeRenderTarget = pmremGenerator.fromEquirectangular( texture );
      this.sceneBg = texture;
    });

    this.camera = new Three.PerspectiveCamera(45, width / height, 1, 1000);
    this.camera.focus = 0.1;
    // this.camera.position.x = 0;
    // this.camera.position.y = 35;
    // this.camera.position.z = 50;
    // this.camera.position.y = 160;
    // this.camera.position.z = 0;
    this.camera.position.copy(this.cameraP);
    this.camera.lookAt(this.cameraFocusP);

    this.rendererMain = new Three.WebGLRenderer({
      alpha: true,
      antialias: true, //抗锯齿
    });
    // this.rendererMain.setClearColor( 0xffffff );
    this.rendererMain.setPixelRatio(window.devicePixelRatio);
    this.rendererMain.setSize(width, height);
    this.container.appendChild(this.rendererMain.domElement);

    this.rendererBg = new Three.WebGLRenderer({
      // alpha: true,
      antialias: true,
    });
    this.rendererBg.setClearColor(0x083146);
    // this.rendererBg.setClearColor(0x000000);
    this.rendererBg.setPixelRatio(window.devicePixelRatio);
    this.rendererBg.setSize(width, height);
    this.containerBg.appendChild(this.rendererBg.domElement);

    this.controls = new OrbitControls(
      this.camera,
      this.rendererMain.domElement,
    );
    this.controls.enableDamping = true; //阻尼
    this.controls.dampingFactor = 0.1; //阻尼

    this.initEventListen();
    this.addLight(); //+光源
    this.initStats();
    this.addThings();
    this.addComposer();
    this.initGui();
    this.animate(); //开始动

    // this.cameraTimeline = gsap.timeline();

    // this.genIterate = this.genFun()
    // console.log('genIterate',this.genIterate)
    // console.log('genIterate',this.genIterate.next())
    // setTimeout(() => {
    //   console.log('genIterate2',this.genIterate.next())
    // }, 2000)
  };
  // private genIterate?:any;
  // private genFun =  function * (){
  //   yield '1000';
  //   yield '2000';
  //   yield '3300';
  //   yield '4440';
  // }

  public destroy = () => {
    this.toggleGui(0);
    Object.values(this.Geometrys).forEach((e) => {
      e.dispose();
    });
    Object.values(this.Materials).forEach((e) => {
      e.dispose();
    });
    this.scene.clear();
    this.rendererMain.dispose();
    this.rendererBg.dispose();
    this.rendererMain.forceContextLoss();
    this.rendererBg.forceContextLoss();
    this.camera = null;
    this.scene = null;
    this.rendererMain = null;
    this.rendererBg = null;
    this.GuiInit = null;
    this.stats = null;
    if (this.tween) {
      this.tween.stop();
      this.tween = null;
    }
    window.removeEventListener('pointermove', this.onPointerMove);
    window.removeEventListener('resize', this.onWindowResize);
    window.removeEventListener('blur', this.onWindowBlur);
    window.removeEventListener('focus', this.onWindowFocus);
    cancelAnimationFrame(this.animateFrame);
  };

  // private quickAniBoatRy:Function = () => {}

  // private focusTarget = new Three.Vector3(0, 0, 0);
  private scrollY: number = 0;
  public scrollTo = (obj) => {
    this.scrollY = obj.y;
    // console.log('index scroll:', obj)
    if (obj.y < this.windowH) {
      // this.focusTarget.set(0,0,-50)
    } else if (obj.y < this.windowH * 2) {
      // const x = (obj.y - 500) / 2
      // const z = 0 - ((obj.y - 500) / 2)
      // this.focusTarget.set(x,0,z)
    } else if (obj.y < this.windowH * 3) {
    } else if (obj.y < this.windowH * 4) {
    } else {
      // this.focusTarget.set(50,0,0)
    }

    if (obj.y < this.windowH) {
      const persent = obj.y / this.windowH;
      this.lightHouseP.x = (15 - 40) * persent + 40; //(40,0,50) => (15,0,-5)
      this.lightHouseP.z = (-5 - 50) * persent + 50;
      this.birdPosState = 1;
    } else if (obj.y > this.windowH * 2) {
      const persent = obj.y - this.windowH * 2;
      this.lightHouseP.x = 15 - persent * 0.2;
      this.lightHouseP.z = -5 - persent * 0.2;
      this.birdPosState = 2;
    } else {
      this.lightHouseP.x = 15;
      this.lightHouseP.z = -5;
      this.birdPosState = 1;
    }

    if (obj.y > this.windowH * 2.5 && obj.y < this.windowH * 3) {
      this.BoatRotateLerp(obj.direction == 'down' ? -0.5 : 0.5, 3, (num) => {
        this.cameraFocusP.x =
          -(num - 0.5) * this.windowW * 0.2 * this.heightRate;
      });
    }
    if (obj.y < this.windowH * 2.5) {
      // this.boatRotate.y = 0.5;
      // this.tweenValues.boatGpPositionState = 1
      // this.quickAniBoatRy(this.boatRotate.y)
    } else if (obj.y > this.windowH * 3) {
      // this.boatRotate.y = -0.5;
      // this.tweenValues.boatGpPositionState = 2
      // this.quickAniBoatRy(this.boatRotate.y)
    } else {
      const persent = (obj.y - this.windowH * 2.5) / (this.windowH * 0.5);
      // this.tweenValues.boatGpPositionState = 1+persent
      // this.boatRotate.y = -persent*0.5;
      // this.quickAniBoatRy(this.boatRotate.y)
      // this.rotateBoat(0.5-persent)

      // this.cameraTimeline.progress(persent)
    }

    // this.rotateBoat(Math.PI*1.05)
  };

  private initStats = () => {
    if (config.ENV === 'production') {
      return;
    }
    this.stats = new Stats();
    if (this.stats) {
      this.stats.showPanel(0); // 0: fps, 1: ms, 2: mb, 3+: custom
      this.stats.dom.style.position = 'absolute';
      this.container.appendChild(this.stats.dom);
    }
  };

  private initEventListen = () => {
    window.addEventListener('pointermove', this.onPointerMove);
    window.addEventListener('resize', this.onWindowResize);
    window.addEventListener('blur', this.onWindowBlur);
    window.addEventListener('focus', this.onWindowFocus);
  };
  private onWindowResize = () => {
    this.windowW = window.innerWidth;
    this.windowH = window.innerHeight;
    this.windowHalfX = window.innerWidth / 2;
    this.windowHalfY = window.innerHeight / 2;

    this.camera.aspect = window.innerWidth / window.innerHeight;
    this.camera.updateProjectionMatrix();

    this.rendererMain.setSize(window.innerWidth, window.innerHeight);
    this.rendererBg.setSize(window.innerWidth, window.innerHeight);
  };
  private onPointerMove = (event) => {
    if (event.isPrimary === false || !this.focusState) return;
    this.mouseData.mouseX = event.clientX - this.windowHalfX;
    this.mouseData.mouseY = event.clientY - this.windowHalfY;

    // console.log(this.mouseData.mouseX, this.mouseData.mouseY)
  };
  private focusState: 0 | 1 = 1;
  private onWindowBlur = () => {
    this.focusState = 0;
  };
  private onWindowFocus = () => {
    this.focusState = 1;
  };

  public initGui = () => {
    if (config.ENV === 'production') {
      return;
    }
    if (this.GuiInit) {
      this.toggleGui();
      return;
    }
    this.GuiInit = new dat.GUI({
      // autoPlace: false
    });

    this.GuiInit.domElement.style.position = 'absolute';
    this.GuiInit.domElement.style.right = '10px';
    this.GuiInit.domElement.style.top = '10px';

    let GuiController = this.GuiInit.addFolder('控制窗口');
    GuiController.add(this.guiData, 'testMode')
      .name('测试相机')
      .onChange((e) => {
        this.rendererMain.domElement.style.pointerEvents = e ? 'all' : 'none';
        //@ts-ignore
        document.querySelector('div.dg.ac').style.zIndex = e ? 5 : 0;
      });
    // GuiController.addColor(this.guiData, 'color').name('背景颜色');
    GuiController.add(this.guiData, 'speedX', -2, 2, 0.005);
    GuiController.add(this.guiData, 'speedY', -2, 2, 0.005);
    GuiController.add(this.guiData, 'scale', 0.01, 0.8, 0.002);
    GuiController.add(this.guiData, 'strength', -4, 8, 0.01);
    GuiController.open();

    GuiController = this.GuiInit.addFolder('后期合成');
    GuiController.add(this.guiData, 'focus', 1.0, 200.0, 1).onChange(
      this.matChanger,
    );
    GuiController.add(this.guiData, 'aperture', 0, 15, 0.02).onChange(
      this.matChanger,
    );
    GuiController.add(this.guiData, 'maxblur', 0.0, 0.1, 0.005).onChange(
      this.matChanger,
    );

    GuiController.add(this.guiData, 'pixelSize', 1, 50, 1).onChange((e) => {
      this.composePasses.renderPixelatedPass.setPixelSize(
        this.guiData.pixelSize,
      );
    });
    GuiController.add(
      this.composePasses.renderPixelatedPass,
      'normalEdgeStrength',
    )
      .min(0)
      .max(2)
      .step(0.05);
    GuiController.add(
      this.composePasses.renderPixelatedPass,
      'depthEdgeStrength',
    )
      .min(0)
      .max(1)
      .step(0.05);

    // let cubeGui = this.GuiInit.addFolder("cube position");
    // cubeGui.open()
  };
  private matChanger = () => {
    this.composePasses.bokehPass.uniforms['focus'].value = this.guiData.focus;
    this.composePasses.bokehPass.uniforms['aperture'].value =
      this.guiData.aperture * 0.00001;
    this.composePasses.bokehPass.uniforms['maxblur'].value =
      this.guiData.maxblur;
  };

  public toggleGui = (state: any = null) => {
    if (!this.GuiInit || !this.GuiInit.domElement) {
      return;
    }
    let display = this.GuiInit.domElement.style.display == 'none' ? '' : 'none';
    if (state == 0) {
      display = 'none';
    }
    this.GuiInit.domElement.style.display = display;
  };

  private addLight = () => {
    let ambi = new Three.AmbientLight(16777215);
    ambi.intensity = 0.6;
    ambi.layers.enable(1);
    this.scene.add(ambi);

    let dirLight = new Three.DirectionalLight(0xffffff);
    dirLight.position.set(-30, 0, 30);
    dirLight.intensity = 0.33;
    dirLight.layers.enable(1);
    this.scene.add(dirLight);

    let dirLight2 = new Three.DirectionalLight(0xffffff);
    dirLight2.position.set(30, 30, 30);
    dirLight2.intensity = 0.23;
    dirLight2.layers.enable(1);
    this.scene.add(dirLight2);

    // let light = new Three.PointLight( 0xFFFF00 );
    // light.position.set( -100, 100, 0 );
    // this.scene.add(light);
  };

  private newMesh = (key: keyof MeshsName, Geo: any, Mat: any) => {
    this.Geometrys[key] = Geo;
    this.Materials[key] = Mat;
    this.Meshs[key] = new Three.Mesh(this.Geometrys[key], this.Materials[key]);
    this.Meshs[key].scale.set(0, 0, 0);
    return this.Meshs[key];
  };

  private addThings = async () => {
    // const axesHelper = new Three.AxesHelper( 800 );
    // this.scene.add( axesHelper )  //添加坐标轴；红线是X轴，绿线是Y轴，蓝线是Z轴

    this.scene.add(this.indexScrollGroup);
    this.scene.add(this.boatGroup);
    this.boatGroup.position.set(0, 6, -70);
    // this.boatGroup.layers.set(1);

    /** test **/

    /** test **/

    /**船**/
    await this.addBoat();
    /**船**/

    /**灯塔**/
    await this.addLightHouse();
    /**灯塔**/

    /**鸟**/
    await this.addBird();
    /**鸟**/

    /**船舵**/
    await this.addWheel();
    /**船舵**/

    /**海**/
    this.addWaves();
    /**海**/

    /** 立方体 **/
    this.boatGroup.add(
      this.newMesh(
        'cube',
        new Three.BoxGeometry(10, 10, 10),
        new Three.MeshPhongMaterial({
          color: 0xffffff,
        }),
      ),
    );
    this.Meshs.cube.layers.set(1);
    /** 立方体 **/

    /** 球体 **/
    this.indexScrollGroup.add(
      this.newMesh(
        'sphere',
        new Three.SphereGeometry(7, 24, 12),
        new Three.MeshPhongMaterial({
          color: 0xffea45,
        }),
      ),
    );
    this.Meshs.sphere.position.y = -this.windowH * 3 * this.heightRate;
    this.Meshs.sphere.layers.set(1);
    /** 球体 **/

    // this.quickAniBoatRy = gsap.quickTo(this.Meshs.boat.rotation, 'y', {
    //   duration: 0.6,
    //   ease: 'power3',
    // });

    // this.cameraTimeline.to(this.cameraP, {
    //   x: this.windowW * 0.3*this.heightRate,
    //   duration: 3, ease: 'power2.inOut'
    // })
    // this.cameraTimeline.to(this.cameraFocusP, {
    //   x: this.windowW * 0.3*this.heightRate,
    //   duration: 3, ease: 'power2.inOut'
    // }, '<')
    // this.cameraTimeline.pause()

    setTimeout(() => {
      this.triggerLoad();
    }, 100);
  };
  private triggerLoad = () => {
    this.triggerSubscribe('afterLoad');
  };

  private addBoat = () => {
    return new Promise<void>((resolve, reject) => {
      const colorMap = this.textureLoader.load(assets.ash_Color);
      const bumpMap = this.textureLoader.load(assets.ash_Bump);
      colorMap.wrapS = bumpMap.wrapS = Three.RepeatWrapping;
      colorMap.wrapT = bumpMap.wrapT = Three.RepeatWrapping;
      colorMap.repeat.set(0.2, 0.2);
      bumpMap.repeat.set(0.2, 0.2);

      let mtlLoader = new MTLLoader();
      mtlLoader.load('../models/boat.mtl', (materials) => {
        materials.preload();
        let objLoader = new OBJLoader();
        console.log(materials);
        objLoader.setMaterials(materials);
        objLoader.load(
          '../models/boat.obj',
          (object) => {
            object.traverse((child) => {
              if (child instanceof Three.Mesh) {
                if (child.name == 'body' || child.name == 'house') {
                  child.material.map = colorMap;
                  // child.material.displacementMap = bumpMap;
                  // child.material.displacementScale = 0.013
                  // child.material.normalMap = colorMap;
                  // child.material.normalScale = new Three.Vector2(0.0000001,0.0000001)
                  child.material.bumpMap = bumpMap;
                  child.material.bumpScale = 0.06;
                  // child.material.roughnessMap = bumpMap;
                  // child.material.roughness = 0.001

                  // child.material.shininess = 1;
                  child.material.shininess = 15;
                  child.material.refractionRatio = 0.1;
                } else {
                  child.material.shininess = 3;
                }
                // child.material.reflectivity = 0.1;
                // object.receiveShadow = true;
                // object.castShadow = true;
                // object.layers.set(1);
              }
            });
            console.log('test OBJ:::', object);
            // object.position.set(0, 2, -100);
            object.scale.set(4, 4, 4);
            object.receiveShadow = true;
            object.castShadow = true;
            this.Meshs.boat = object;
            // this.Meshs.boat.layers.set(1);
            // this.Meshs.boat.lookAt(new Three.Vector3(1,0,0))
            this.boatGroup.add(this.Meshs.boat);
            resolve();
          },
          (xhr) => {
            console.log((xhr.loaded / xhr.total) * 100 + '% loaded');
          },
          (error) => {
            console.log(error);
          },
        );
      });
    });
  };
  private addWheel = () => {
    return new Promise<void>((resolve, reject) => {
      let objLoader = new OBJLoader();
      objLoader.load(
        '../models/wheel.obj',
        (object) => {
          object.traverse((child) => {
            if (child instanceof Three.Mesh) {
              // child.material.reflectivity = 0.1;
              child.receiveShadow = true;
              child.castShadow = true;
              child.layers.set(1);
              // child.layers.disable(0)
            }
          });
          object.position.set(0, -this.windowH * this.heightRate, 0);
          object.scale.set(2, 2, 2);
          object.rotation.set(1.5, 0, 0);
          object.receiveShadow = true;
          object.castShadow = true;
          this.Meshs.wheel = object;

          // this.Meshs.wheel.lookAt(new Three.Vector3(1,0,0))
          this.indexScrollGroup.add(this.Meshs.wheel);
          this.Meshs.wheel.layers.set(1);
          // this.Meshs.wheel.layers.disable(0)
          resolve();
        },
        (xhr) => {
          console.log((xhr.loaded / xhr.total) * 100 + '% loaded');
        },
        (error) => {
          console.log(error);
        },
      );
    });
  };
  private addLightHouse = () => {
    return new Promise<void>((resolve, reject) => {
      let mtlLoader = new MTLLoader();
      mtlLoader.load('../models/lighthouse.mtl', (materials) => {
        materials.preload();
        let objLoader = new OBJLoader();
        console.log(materials);
        objLoader.setMaterials(materials);
        objLoader.load(
          '../models/lighthouse.obj',
          (object) => {
            object.traverse((child) => {
              // if (child instanceof Three.Mesh) {
              // }
            });
            // object.position.set(15,0,-5);
            // object.scale.set(3, 3, 3);
            object.position.copy(this.lightHouseP);
            object.scale.set(0, 0, 0);
            object.receiveShadow = true;
            object.castShadow = true;
            this.Meshs.lighthouse = object;
            console.log('rotation', object.position, object.rotation);
            this.scene.add(this.Meshs.lighthouse);
            resolve();
          },
          (xhr) => {
            console.log((xhr.loaded / xhr.total) * 100 + '% loaded');
          },
          (error) => {
            console.log(error);
          },
        );
      });
    });
  };
  private mixer: any;
  private addBird = () => {
    return new Promise<void>((resolve, reject) => {
      const loader = new FBXLoader();
      loader.load('../models/bird.fbx', (object) => {
        this.mixer = new Three.AnimationMixer(object);

        const action = this.mixer.clipAction(object.animations[0]);
        action.play();

        object.traverse((child) => {
          if (child.isMesh) {
            child.castShadow = true;
            child.receiveShadow = true;
          }
        });
        this.Meshs.bird = object;
        // this.Meshs.bird.scale.set(0.05,0.05,0.05)
        this.Meshs.bird.scale.set(0, 0, 0);
        this.Meshs.bird.position.copy(this.Meshs.lighthouse.position);

        this.scene.add(this.Meshs.bird);
        resolve();
      });
    });
  };

  private posBaseX: number = 0;
  private posBaseY: number = 0;
  private addWaves = () => {
    // wavePointNum
    this.Geometrys.wave = new Three.PlaneGeometry(
      600,
      600,
      this.guiData.wavePointNum,
      this.guiData.wavePointNum,
    );
    let pos = this.Geometrys.wave.attributes.position.array;
    this.Geometrys.wave.setAttribute(
      'color',
      new Three.BufferAttribute(new Float32Array(pos.length), 3),
    );

    this.setWavePoints();

    this.Materials.wave = new Three.MeshPhongMaterial({
      color: 0xedf8fa,
      side: Three.DoubleSide,
      flatShading: true, //平面，没有顶点过度！！！！！
      // wireframe: true,
      vertexColors: true, //用顶点颜色

      transparent: true,
      opacity: 0.95,
    });
    this.Meshs.wave = new Three.Mesh(this.Geometrys.wave, this.Materials.wave);
    this.Meshs.wave.receiveShadow = true;
    this.Meshs.wave.castShadow = true;

    this.Meshs.wave.position.set(0, 0, -200);
    this.Meshs.wave.rotation.set(Math.PI * 0.5, 0, 0);
    this.Meshs.wave.layers.set(0);
    this.scene.add(this.Meshs.wave);
  };
  private setWavePoints = () => {
    let pos = this.Geometrys.wave.attributes.position.array;
    const colors1 = this.Geometrys.wave.attributes.color;
    for (let i = 0; i < pos.length; i += 3) {
      pos[i + 2] = this.getWaveZ(i / 3);

      const color = calcWaveColor(pos[i], pos[i + 1], pos[i + 2]);
      colors1.setXYZ(i / 3, color.r, color.g, color.b);
      if (i / 3 == 1174) {
        // 80*14.675
        this.boatY = pos[i + 2];
        // colors1.setXYZ( i/3, 255, 255, 255 );  //test
      }
    }
    this.Geometrys.wave.attributes.position.needsUpdate = true;
    this.Geometrys.wave.attributes.color.needsUpdate = true;
    this.Geometrys.wave.computeVertexNormals(); //重新计算法线向量
  };

  private addComposer = () => {
    //后期
    // 创建渲染通道
    const renderPass = new RenderPass(this.scene, this.camera);

    // 创建景深参数
    const params = {
      focus: this.guiData.focus, // 聚焦
      // aspect: ts.camera.aspect,
      aperture: this.guiData.aperture, // 孔径
      maxblur: this.guiData.maxblur,
      // width: window.innerWidth,
      // height: window.innerHeight
    };

    // 创建景深通道
    this.composePasses.bokehPass = new BokehPass(
      this.scene,
      this.camera,
      params,
    );

    // 创建效果合成器
    this.composer = new EffectComposer(this.rendererBg);

    this.composePasses.renderPixelatedPass = new RenderPixelatedPass(
      this.guiData.pixelSize,
      this.scene,
      this.camera,
    );
    this.composePasses.renderPixelatedPass.normalEdgeStrength = 0;

    // 添加通道
    this.composer.addPass(renderPass);
    // this.composer.addPass(this.composePasses.bokehPass)  //景深
    this.composer.addPass(this.composePasses.renderPixelatedPass); //像素化

    this.matChanger();
  };

  public startAnimate = () => {
    // console.log('update start:::', this.boatGroup.position.y)
    // this.Meshs.boat.position.set(-200, 2, -500);
    new TWEEN.Tween(this.tweenValues)
      .to({ boatGpPositionState: 1 }, 4000)
      .easing(TWEEN.Easing.Quadratic.Out)
      .start()
      .onUpdate((e) => {
        // (0, 8, -70)
        this.boatGroup.position.z =
          -70 * (1 - this.tweenValues.boatGpPositionState);
      })
      .onComplete(() => {});
    // return;
    new TWEEN.Tween(this.cameraP)
      .to({ y: 35, z: 50 }, 2000)
      .easing(TWEEN.Easing.Quadratic.InOut)
      .delay(1000)
      .start()
      .onUpdate((e) => {
        // (0, 160, 0)
        this.camera.position.copy(this.cameraP);

        this.rotateBoat(this.cameraP.z / 100);
      })
      .onComplete(() => {
        this.triggerSubscribe('afterAnimate');
        this.guiData.enableMouseMove = true;
        this.Meshs.lighthouse.scale.set(3, 3, 3);
        this.Meshs.bird.scale.set(0.05, 0.05, 0.05);

        // this.cameraTimeline.play()
      });
    // new TWEEN.Tween(this.boatGroup.rotation)
    //   .to({ y: 0.6 }, 2000)
    //   .easing(TWEEN.Easing.Quadratic.InOut)
    //   .delay(1000)
    //   .start()
    //   .onComplete(() => {});
  };

  private BoatRotateLerp = (
    num: number,
    time: number,
    callback?: (num: number) => void,
  ) => {
    if (this.tweenValues.boatGpRotateY == num) {
      return;
    }
    this.tweenValues.boatGpRotateY = num;
    new TWEEN.Tween(this.boatGroup.rotation)
      .to({ y: num }, time * 1000)
      .easing(TWEEN.Easing.Quadratic.InOut)
      .start()
      .onUpdate((e) => {
        this.rotateBoat(e.y);
        callback && callback(e.y);
      });
  };
  private rotateBoat = (rotateY: number) => {
    //
    this.boatGroup.rotation.y = rotateY;

    const speed = 1; //(8-delta)/8;
    this.guiData.speedX = -Math.cos(this.boatGroup.rotation.y) * speed;
    this.guiData.speedY = Math.sin(this.boatGroup.rotation.y) * speed;
  };

  private getWaveZ = (i: number) => {
    //100宽 有 101个点！！！
    const opintNum = this.guiData.wavePointNum + 1;
    let tx = Math.floor(i / opintNum) * this.guiData.scale + this.posBaseX;
    let ty = Math.floor(i % opintNum) * this.guiData.scale + this.posBaseY;
    const z = noise2D(tx, ty);
    return z * this.guiData.strength;
  };
  private waveAnimate = (delta: number) => {
    if (this.Meshs.wave) {
      this.posBaseX += delta * this.guiData.speedX;
      this.posBaseY += delta * this.guiData.speedY;
      this.setWavePoints();
    }
  };
  private boatY: number = 0;
  // private boatY: number = 0;
  private boatAnimate = (delta: number) => {
    const posState = this.tweenValues.boatGpPositionState;
    // // 80*14.675
    // const y = this.getWaveZ(1174)
    const rateY = posState > 1 ? 0 : 1 - posState;
    this.boatGroup.position.y = 6 * rateY - this.boatY;
    // const rateX = posState <1? 0: (posState - 1);
    // this.boatGroup.position.x = -this.windowW * 0.3 * rateX * this.heightRate;
  };

  private birdPosState: number = 1; //1；2；
  private birdPos: any = new Three.Vector3(0, 0, 0);
  private birdAnimate = (delta: number) => {
    const prevPos = this.birdPos;
    if (this.Meshs.bird && this.Meshs.lighthouse) {
      const timer = Date.now() * 0.001;
      const deltaY = Math.cos(timer) * 3;

      const posBase =
        this.birdPosState == 1
          ? this.lightHouseP.clone().add(new Three.Vector3(-4, deltaY + 10, 1))
          : this.boatGroup.position
              .clone()
              .multiply(new Three.Vector3(1, 0, 1))
              .add(new Three.Vector3(4, deltaY + 6, -6));

      this.birdPos.copy(posBase);

      this.Meshs.bird.position.lerp(this.birdPos, 0.03);

      const lookPos = this.boatGroup.position
        .clone()
        .add(new Three.Vector3(0, deltaY + 6, 0)); //.setComponent(1, 10);
      this.Meshs.bird.lookAt(lookPos);
    }
  };

  private animate = () => {
    this.animateFrame = requestAnimationFrame(this.animate);
    if (!this.focusState) {
      return;
    }

    if (this.stats) {
      this.stats.begin();
    }

    this.render();
    TWEEN.update();
    if (this.guiData.testMode) {
      this.controls.update();
    }

    if (this.stats) {
      this.stats.end();
    }
  };
  private render = () => {
    const delta = this.clock.getDelta();

    // if(this.guiData.autoRotate){
    // }

    this.waveAnimate(delta);
    this.boatAnimate(delta);

    if (this.mixer) this.mixer.update(delta);

    if (this.guiData.testMode) {
    } else {
      if (this.guiData.enableMouseMove) {
        this.camera.position.lerp(
          this.cameraP
            .clone()
            .set(
              this.mouseData.mouseX * 0.02 + this.cameraP.x,
              this.cameraP.y - this.mouseData.mouseY * 0.02,
              this.cameraP.z,
            ),
          0.1,
        );
        // this.camera.position.x +=
        //   (this.mouseData.mouseX * 0.03 - this.camera.position.x) * 0.1;
        // this.camera.position.y +=
        //   (35 - this.mouseData.mouseY * 0.02 - this.camera.position.y) * 0.1;
      }
      // // this.cameraFocusP.lerp(this.focusTarget, 0.07)
      this.camera.lookAt(this.cameraFocusP);
    }

    this.indexScrollGroup.position.y +=
      (this.scrollY * this.heightRate - this.indexScrollGroup.position.y) * 0.3;

    if (this.Meshs.lighthouse) {
      this.Meshs.lighthouse.position.lerp(this.lightHouseP, 0.05);
    }
    this.birdAnimate(delta);

    this.camera.layers.set(0);
    // this.scene.background = this.sceneBg;
    // this.rendererBg.render(this.scene, this.camera);
    this.composer.render(10); //后期

    this.camera.layers.set(1);
    // this.scene.background = null;
    this.rendererMain.render(this.scene, this.camera);
  };
}

const indexWebgl = new WebGlControl();
export { indexWebgl };
